<?php
declare(strict_types=1);

namespace App\Utils\Other\Payment\Sandpay;
use App\Exception\InternalException;
use Hyperf\Collection\Arr;
use Hyperf\Context\Context;
use function App\Utils\Common\SandpayRsa\sign;
use function App\Utils\Common\SandpayRsa\verify;
use function Hyperf\Translation\__;

/**
 * 支付单报关
 * @package App\Utils\Other\Payment\Sandpay
 */
Class Declares extends App {

    public function __construct()
    {
        $this->setConfig(['url' => 'https://customs.sandpay.com.cn/']);
    }

    /**
     * 推送支付单
     * @param array $params
     * @return array
     * @throws \GuzzleHttp\Exception\GuzzleException
     */
    public function push(array $params): array
    {
        $this->setPath('open/trade/customs/pushPay');

        $params['ioType'] = '1';
        $params['realNameVerifi'] = '01';
        $params['method'] = 'open.trade.customs.pushPay';
        $params['payInfo']['bsEbPlCode'] = $this->getConfig('bs_eb_pl_code');
        $params['payInfo']['bsEbPlName'] = $this->getConfig('bs_eb_pl_name');
        $params['payInfo']['bsEbComCode'] = $this->getConfig('bs_eb_com_code');
        $params['payInfo']['bsEbComName'] = $this->getConfig('bs_eb_com_name');

        return $this->request($params);
    }

    /**
     * 查询支付单
     * @param array $params
     * @return array
     */
    public function query(array $params): array
    {
        $this->setPath('open/query/customs/queryPushPay');

        $params['method'] = 'open.query.customs.queryPushPay';

        return $this->request($params);
    }

    /**
     * 获取参数
     * @param array $params
     * @return array
     */
    protected function params(array $params = []): array
    {
        $body = [
            'version' => '1.0',
            'productId' => '00000029',
            'mid' => $this->getConfig('mid'),
            'reqTime' => date('YmdHis')
        ];

        $params = array_merge($body, $params);
        $params = $this->sortParams($params);
        $params['sign'] = sign(json_encode($params, JSON_UNESCAPED_UNICODE), Context::get('private_key'));

        return $params;
    }

    /**
     * 参数排序
     * @param array $params
     * @return array
     */
    protected function sortParams(array $params): array
    {
        ksort($params);
        foreach ($params as $key => $val) {
            if (is_array($val)) {
                $newVal = $val;
                ksort($newVal);
                $params[$key] = $newVal;
            }
        }

        return $params;
    }

    /**
     * 处理响应
     * @param $response
     * @param array $params
     * @return array
     */
    protected function response($response, array $params = []): array
    {
        // TODO: Implement response() method.
        logs($response);
        if (!$response) {
            throw new InternalException(__('request.nobody'));
        }
        $result = json_decode($response, true);
        $jsonError = json_last_error();
        if ($jsonError !== JSON_ERROR_NONE) {
            throw new InternalException(__('request.json_error', [
                'code' => $jsonError,
                'message' => json_last_error_msg()
            ]));
        }
        $sign = Arr::get($result, 'sign');
        unset($result['sign']);

        verify(json_encode($result, JSON_UNESCAPED_UNICODE), $sign, Context::get('public_key'));

        if (Arr::get($result, 'respCode') !== '000000') {
            throw new InternalException(__('request.error', [
                'code' => Arr::get($result, 'respCode'),
                'message' => Arr::get($result, 'respMsg')
            ]));
        }

        return [
            $params, $result, $result, $this->getConfig('url').$this->getConfig('path')
        ];
    }
}